/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Seguridad;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;


/**
 *
 * @author Antonio
 */
public class RSA {
    
    private int tamPrimo;
    private BigInteger totient;
    private BigInteger publicKey;
    private BigInteger privateKey;
    private BigInteger moduloKey;
    private BigInteger p,q;

    public RSA (int tam)
    {
        tamPrimo = tam;
        generaPrimos();
        generaClaves();
    }
    
    private String execute(String input, BigInteger key) {
        String[] splitInput = input.split(" ");
        StringBuffer result = new StringBuffer();

        for (int i = 0; i < splitInput.length; i++) {
            
            result.append(execute(BigInteger.valueOf(Long.parseLong(
                            splitInput[i])), key, moduloKey));
            result.append(' ');
        }

        return result.toString().trim();
    }

    private BigInteger execute(BigInteger input, BigInteger key,
        BigInteger moduloKey) {
        return input.modPow(key, moduloKey);
    }

    public String execute(String input) {
        return execute(input, publicKey);
    }

    public String reverse(String input) {
        return execute(input, privateKey);
    }

    public PropertyDescriptor[] getRequiredProperties() {
        try {
            return new PropertyDescriptor[] {
                new PropertyDescriptor("publicKey", RSA.class),
                new PropertyDescriptor("privateKey", RSA.class),
                new PropertyDescriptor("moduloKey", RSA.class)
            };
        } catch (IntrospectionException exc) {
            
        }

        return null;
    }

    /**
     * @return Returns the publicKey.
     */
    public long getPublicKey() {
        return publicKey.longValue();
    }

    /**
     * @param publicKey The publicKey to set.
     */
    public void setPublicKey(long publicKey) {
        this.publicKey = BigInteger.valueOf(publicKey);
    }

    /**
     * @return Returns the privateKey.
     */
    public long getPrivateKey() {
        return privateKey.longValue();
    }

    /**
     * @param privateKey The privateKey to set.
     */
    public void setPrivateKey(long privateKey) {
        this.privateKey = BigInteger.valueOf(privateKey);
    }

    /**
     * @return Returns the moduloKey.
     */
    public long getModuloKey() {
        return moduloKey.longValue();
    }

    /**
     * @param moduloKey The moduloKey to set.
     */
    public void setModuloKey(long moduloKey) {
        this.moduloKey = BigInteger.valueOf(moduloKey);
    }
    
    public void generaPrimos()
    {
        p = new BigInteger(tamPrimo, 10, new SecureRandom());
        do q = new BigInteger(tamPrimo, 10, new SecureRandom());
            while(q.compareTo(p)==0);
    }

    public void generaClaves()
    {
        // n = p * q
        moduloKey = p.multiply(q);
        // toltient = (p-1)*(q-1)
        totient = p.subtract(BigInteger.valueOf(1));
        totient = totient.multiply(q.subtract(BigInteger.valueOf(1)));
        // Elegimos un e coprimo de y menor que n
        do publicKey = new BigInteger(2 * tamPrimo, new Random());
            while((publicKey.compareTo(totient) != -1) ||
		 (publicKey.gcd(totient).compareTo(BigInteger.valueOf(1)) != 0));
        // d = e^1 mod totient
        privateKey = publicKey.modInverse(totient);
    }

    public BigInteger[] encripta(String mensaje)
    {
        int i;
        byte[] temp = new byte[1];
        byte[] digitos = mensaje.getBytes();
        BigInteger[] bigdigitos = new BigInteger[digitos.length];
        
        for(i=0; i<bigdigitos.length;i++){
            temp[0] = digitos[i];
            bigdigitos[i] = new BigInteger(temp);
        }
        
        BigInteger[] encriptado = new BigInteger[bigdigitos.length];
        
        for(i=0; i<bigdigitos.length; i++)
            encriptado[i] = bigdigitos[i].modPow(publicKey,moduloKey);
        
        return(encriptado);
    }
    
    /**
     * Desencripta el texto cifrado usando la clave privada
     *
     * @param   encriptado       Array de objetos BigInteger que contiene el texto cifrado
     *                           que será desencriptado
     * @return  The decrypted plaintext
     */
    public String desencripta(BigInteger[] encriptado) {
        BigInteger[] desencriptado = new BigInteger[encriptado.length];
        
        for(int i=0; i<desencriptado.length; i++)
            desencriptado[i] = encriptado[i].modPow(privateKey,moduloKey);
        
        char[] charArray = new char[desencriptado.length];
        
        for(int i=0; i<charArray.length; i++)
            charArray[i] = (char) (desencriptado[i].intValue());
        
        return(new String(charArray));
    }
    
 
}

